// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 此文件包含driver.UI实现
// 如果可能的话，它提供了readline功能。

// go:构建（达尔文| | |蜻蜓| | freebsd | | | linux | | | netbsd | | openbsd | | solaris | windows）&&！阿彭金&！安卓
// +构建darwin dragonfly freebsd linux netbsd openbsd solaris windows
// +建造！阿彭金
// +建造！安卓

package main

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/google/pprof/driver"
	"golang.org/x/term"
)

func init() {
	newUI = newReadlineUI
}

// readlineUI使用
// golang.org/x/term package。
// 命令的上游pprof实现相同的功能
// 使用github.com/chzyer/readline包。
type readlineUI struct {
	term *term.Terminal
}

func newReadlineUI() driver.UI {
	// 在哑终端中禁用readline UI。（golang.org/issue/26254）
	if v := strings.ToLower(os.Getenv("TERM")); v == "" || v == "dumb" {
		return nil
	}
	// 测试是否可以使用term.ReadLine
	// 假定在原始模式下运行。
	oldState, err := term.MakeRaw(0)
	if err != nil {
		return nil
	}
	term.Restore(0, oldState)

	rw := struct {
		io.Reader
		io.Writer
	}{os.Stdin, os.Stderr}
	return &readlineUI{term: term.NewTerminal(rw, "")}
}

// Read返回从用户处读取的一行文本（命令）。
// 在读取命令之前打印提示符。
func (r *readlineUI) ReadLine(prompt string) (string, error) {
	r.term.SetPrompt(prompt)

	// 跳过错误检查，因为我们测试了它
	// 最初创建此readlineUI时。
	oldState, _ := term.MakeRaw(0)
	defer term.Restore(0, oldState)

	s, err := r.term.ReadLine()
	return s, err
}

// Print向用户显示一条消息。
// 它将文本格式化为fmt.Print，如果尚未出现，则添加一个final\n。
// 对于基于行的UI，打印写入标准错误。
// （标准输出保留用于报告数据。）
func (r *readlineUI) Print(args ...interface{}) {
	r.print(false, args...)
}

// PrintErr向用户显示一条错误消息。
// 它将文本格式化为fmt.Print，如果尚未出现，则添加一个final\n。
// 对于基于行的UI，PrintErr写入标准错误。
func (r *readlineUI) PrintErr(args ...interface{}) {
	r.print(true, args...)
}

func (r *readlineUI) print(withColor bool, args ...interface{}) {
	text := fmt.Sprint(args...)
	if !strings.HasSuffix(text, "\n") {
		text += "\n"
	}
	if withColor {
		text = colorize(text)
	}
	fmt.Fprint(r.term, text)
}

// colorize使用ANSI颜色转义以红色打印msg。
func colorize(msg string) string {
	const red = 31
	var colorEscape = fmt.Sprintf("\033[0;%dm", red)
	var colorResetEscape = "\033[0m"
	return colorEscape + msg + colorResetEscape
}

// IsTerminal报告UI是否已知绑定到
// 交互式终端（与重定向到文件相反）。
func (r *readlineUI) IsTerminal() bool {
	const stdout = 1
	return term.IsTerminal(stdout)
}

// WantBrowser指示是否应使用-http选项打开浏览器。
func (r *readlineUI) WantBrowser() bool {
	return r.IsTerminal()
}

// SetAutoComplete指示UI调用complete（cmd）以获取
// cmd的自动完成，如果UI支持自动完成。
func (r *readlineUI) SetAutoComplete(complete func(string) string) {
	// TODO:实现自动完成支持。
}
